#include "StdAfx.h"
#include "System.h"

#include "Game.h"


// DMA USED FOR 3D/2D
#define		DMAWIFI_ID	0
#define		DMA3D_ID	1
#define		DMA2D_ID	2
#define		DMADATA_ID	3


CSystem CSystem::__this;
	
	
	
void VBlankIntr()
{
	CSystem::getInstance()->vblank();
}

CSystem::CSystem()
{
	m_videoMode = VIDEOMODE_NONE;
	m_screenPos = MAINSCREEN_DOWN;
	m_targetScreenPos = MAINSCREEN_UP;
	m_brightness = 0;
	m_targetBrightness = 0;
	m_isRendering = FALSE;
}

void CSystem::initSystem()
{
	void   *tmp;
	OSHeapHandle hh;

	//init OS
	OS_Init();
	OS_InitThread();
	OS_InitTick();
	OS_InitAlarm();
	OS_InitReset();
	
	//init heap
	tmp = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
	OS_SetArenaLo(OS_ARENA_MAIN, tmp);
	hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
	if (hh < 0)
	OS_Panic("ARM9: Fail to create heap...\n");
	hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh);
	
	//init interrupts
	OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
	(void)OS_EnableIrqMask(OS_IE_V_BLANK);
	(void)OS_EnableIrq();
	
	//other inits
	FX_Init();
	GX_Init();
	G3X_Init();
	GX_SetPower( GX_POWER_ALL );
    FS_Init( 2 );
	PM_Init();
	RTC_Init();
	CARD_Init();
	SND_Init();
}

void CSystem::setVideoMode(EVideoMode mode)
{
	m_videoMode = mode;
	
	BOOL bExtendedTexturePalette = FALSE;
	
	GX_VBlankIntr(FALSE);

	
	// clear tex zone first
	GX_DisableBankForTex();
	GX_DisableBankForOBJ();

	// clear sub screen
	GX_DisableBankForSubBG();

	GX_SetBankForLCDC(GX_VRAM_LCDC_C);
//	MI_DmaFill32(DMA2D_ID, (void*)HW_LCDC_VRAM_C, 0x80008000, 256*192*2);
    MI_CpuClearFast((void *)HW_LCDC_VRAM_C, 256*192*2);
	GX_DisableBankForLCDC();

	GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);

	// setup subscreen		
	GXS_SetGraphicsMode(GX_BGMODE_5);
	//GXS_SetVisiblePlane(GX_PLANEMASK_BG3 | GX_PLANEMASK_OBJ);
	G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256,
		GX_BG_AREAOVER_XLU,
		GX_BG_BMPSCRBASE_0x00000);
	G2S_SetBG3Priority(0);
	G2S_BG3Mosaic(FALSE);
	GXS_DispOn();

	// clear main screen
	GX_DisableBankForBG();

	/*
	GX_SetBankForLCDC(GX_VRAM_LCDC_D);
	MI_DmaFill32(DMA2D_ID, (void*)HW_LCDC_VRAM_D, 0x80008000, 256*192*2);
	GX_DisableBankForLCDC();

	GX_SetBankForBG(GX_VRAM_BG_128_D);
	*/

	// setup main screen
	GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_5, GX_BG0_AS_3D);
	//GX_SetVisiblePlane(GX_PLANEMASK_BG0 | GX_PLANEMASK_OBJ);
	G2_SetBG2ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256,
		GX_BG_AREAOVER_XLU,
		GX_BG_BMPSCRBASE_0x00000);
	G2_SetBG0Priority(0);
	G2_SetBG2Priority(1);
	G2_BG0Mosaic(FALSE);
	GX_DispOn();

	GX_DisableBankForTex();
	GX_SetBankForTex(GX_VRAM_TEX_012_ABD);

	if( bExtendedTexturePalette )
	{
		GX_SetBankForTexPltt(GX_VRAM_TEXPLTT_01_FG);        // VRAM-EFG for texture palettes
	}
	else
	{
		GX_SetBankForTexPltt(GX_VRAM_TEXPLTT_0_G);        // VRAM-EFG for texture palettes
	}


	if( bExtendedTexturePalette )
	{
		GX_SetBankForOBJ(GX_VRAM_OBJ_64_E);
	}
	else
	{
		GX_SetBankForOBJ(GX_VRAM_OBJ_80_EF);
	}

	GX_SetBankForSubOBJ(GX_VRAM_SUB_OBJ_16_I);
	GX_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_1D_128K);
	GXS_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_1D_128K);
	GX_SetOBJVRamModeBmp(GX_OBJVRAMMODE_BMP_1D_128K);   // 1D mapping
	GXS_SetOBJVRamModeBmp(GX_OBJVRAMMODE_BMP_1D_128K);   // 1D mapping

	setup3D();

	G2S_SetBlendBrightness(GX_PLANEMASK_BG3 | GX_PLANEMASK_OBJ, m_brightness);
	G2_SetBlendBrightness(GX_PLANEMASK_BG0 | GX_PLANEMASK_BG2 | GX_PLANEMASK_OBJ, m_brightness);

//	InitShininessTables_();
//	InitMaterialsAndLights_(0,8,23);

	GX_VBlankIntr(TRUE);
	
	GXS_SetVisiblePlane(GX_PLANEMASK_BG3 | GX_PLANEMASK_OBJ);
	GX_SetVisiblePlane(GX_PLANEMASK_BG0 | GX_PLANEMASK_BG2 | GX_PLANEMASK_OBJ);
	
}

void CSystem::setup3D()
{
	G3X_SetShading(GX_SHADING_HIGHLIGHT);//GX_SHADING_TOON);

	G3X_AntiAlias(TRUE);

	G3X_AlphaBlend(TRUE);

	G2_SetBlendAlpha(GX_BLEND_PLANEMASK_BG2, GX_BLEND_PLANEMASK_BG0, 15, 31);
	
	G3_SwapBuffers(GX_SORTMODE_MANUAL, GX_BUFFERMODE_W);

	G3X_SetClearColor(GX_RGB(0, 0, 0),                     // clear color
		0,                                  // clear alpha
		0x7fff,                              // clear depth
		63,                                  // clear polygon ID
		TRUE                                // fog
		);

	G3_ViewPort(0, 0, 255, 191);
}

void CSystem::setFOV(int fov)
{
	m_fov = fov;
		
    fx32    right = FX32_ONE;
    fx32    top = FX32_ONE * 3 / 4;
    fx32    near = FX32_ONE;
    fx32    far = FX32_ONE * 400;

    G3_Perspective(FX32_SIN30, FX32_COS30,  // sine and cosine of FOVY
                   FX32_ONE * 4 / 3,        // aspect
                   near,           // near
                   far,            // far
                   NULL            // a pointer to a matrix if you use it
        );

    G3_StoreMtx(0);   
}

void CSystem::copyScreens()
{
	u16* mainBuffer;
	u16* subBuffer;

	BOOL changeScreenPos = FALSE;

	if( m_targetScreenPos != m_screenPos )
	{
		m_screenPos = m_targetScreenPos;
		changeScreenPos = TRUE;
	}

	CGame *game = CGame::getInstance();
	
	if( m_brightness != -16 )
	{
		mainBuffer	= game->getMainBuffer();	
		subBuffer	= game->getSubBuffer();

		GX_VBlankIntr( FALSE );

		DC_FlushRange(subBuffer, 256*192*2);
		GXS_LoadBG3Scr(subBuffer, 0, 256*192*2);					

		if ( m_videoMode == VIDEOMODE_2D || m_videoMode == VIDEOMODE_2D3D )
		{
			DC_FlushRange(mainBuffer, 256*192*2);
			GX_LoadBG2Scr(mainBuffer, 0, 256*192*2);
		}
	}

	if( changeScreenPos )
	{
		if (m_screenPos == MAINSCREEN_UP)
			GX_SetDispSelect( GX_DISP_SELECT_MAIN_SUB );
		else
			GX_SetDispSelect( GX_DISP_SELECT_SUB_MAIN );
		game->setMainScreenUp(m_screenPos == MAINSCREEN_UP);
	}

	GX_VBlankIntr( TRUE );
}

void CSystem::clear3DScreen(BOOL flip)
{
	G3X_ClearFifo();
	G3X_Reset();

	G3X_SetClearColor(
		GX_RGB(0, 0, 0),	// clear color
		0,					// clear alpha
		0x7fff,				// clear depth
		63,					// clear polygon ID
		TRUE				// fog
		);

	if (flip)
		G3_SwapBuffers(GX_SORTMODE_MANUAL, GX_BUFFERMODE_W);
}

void CSystem::flip3DScreen()
{
	G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
}

void CSystem::vblank()
{
	OS_SetIrqCheckFlag( OS_IE_V_BLANK );

	if ( !m_isRendering )
	{
		CGame::getInstance()->VBlank();

		if( m_brightness != m_targetBrightness )
		{
			m_brightness = m_targetBrightness;
			G2S_SetBlendBrightness(GX_PLANEMASK_BG3 | GX_PLANEMASK_OBJ, m_brightness);
			G2_SetBlendBrightness(GX_PLANEMASK_BG0 | GX_PLANEMASK_BG2 | GX_PLANEMASK_OBJ, m_brightness);
		}
	}
}